import grails.test.ControllerUnitTestCase
import grails.converters.XML

/**
 * Created by IntelliJ IDEA.
 * User: corcutt
 * Date: Apr 27, 2009
 * Time: 4:45:12 PM
 * To change this template use File | Settings | File Templates.
 */

class EventControllerTests extends ControllerUnitTestCase {

  void testMyEvents() {
    def volunteer = createVolunteer()
    mockSession.volunteer = volunteer
    mockSession.volunteer.id = 1
    mockDomain(Volunteer, [mockSession.volunteer])
    def expectedEventList = createEventList()
    mockDomain(Event, [expectedEventList])
    def serviceControl = mockFor(QueryService)
    def someList = []
    20.times {i -> someList << new Event() }
    serviceControl.demand.myEvents () { ->
        return someList
    }

    serviceControl.demand.eventCount () { ->
        return someList.size()
    }

    controller.queryService = serviceControl.createMock()

    Map model = controller.myEvents()
    assertNotNull('list should be present in model', model.eventInstanceList)
    assertEquals someList.size, model.eventInstanceTotal
  }


  void testFutureEvents() {
    def expectedEventList = createEventList()
    def serviceControl = mockFor(QueryService)
    serviceControl.demand.futureEvents () { ->
        return expectedEventList
    }

    serviceControl.demand.eventCount () { ->
        return expectedEventList.size()
    }

    controller.queryService = serviceControl.createMock()

    Map model = controller.futureEvents()
    assertNotNull model.eventInstanceList
    assertEquals expectedEventList.size(), model.eventInstanceTotal
  }

  void testShow() {
    Event expectedEvent = new Event()
    mockDomain Event, [expectedEvent]
    controller.params.id = 1
    Map model = controller.show()
    assertEquals(expectedEvent, model.eventInstance)
  }

  void testShow_eventInstanceNotFound() {
    mockDomain(Event)
    controller.params.id = 999 // no object with id 999 exists
    controller.show()
    assertNoSuchEvent()
  }

  void testPositionTable_eventInstanceNotFound() {
    setUpEventAndSession()
    controller.params.id = 999 // no object with id 999 exists
    controller.positionTable()
    assertNoSuchEvent()
  }

  void testPositionTable_eventInstanceFound() {
    setUpEventAndSession()
    controller.params.id = 1 // no object with id 999 exists
    controller.positionTable()
    assertEquals('render template', '/common/positionTable', renderArgs.template)
    assertNotNull(renderArgs.model.eventInstance)
    assertNull(renderArgs.model.unfilledPositions)
  }

  void testDelete_eventInstanceNotFound() {
    setUpEventAndSession()
    controller.params.id = 999 // no object with id 999 exists
    controller.delete()
    assertNoSuchEvent()
  }

  void testDelete_NotOwner() {
    setUpEventAndSession()
    mockSession.volunteer.id = 99
    controller.params.id = 1
    controller.delete()
    assertEquals('flash message',
            "You can only delete your own events",
            mockFlash.message)
    assertEquals('redirect action',
            controller.myEvents, redirectArgs.action)

  }

  void testDelete_success() {
    setUpEventAndSession()
    controller.params.id = 1
    controller.delete()
    assertEquals('flash message',
            "Event ${controller.params.id} deleted",
            mockFlash.message)
    assertEquals('redirect action',
            controller.myEvents, redirectArgs.action)

  }

  void testEdit_eventInstanceNotFound() {
    setUpEventAndSession()
    controller.params.id = 999 // no object with id 999 exists
    controller.edit()
    assertNoSuchEvent()
  }

  void testEdit_NotOwner() {
    setUpEventAndSession()
    mockSession.volunteer.id = 99
    controller.params.id = 1
    controller.edit()
    assertEquals('flash message',
            "You can only edit your own events",
            mockFlash.message)
    assertEquals('redirect action',
            controller.myEvents, redirectArgs.action)
  }

  void testEdit_success() {
    Event expectedEvent = createEvent()
    mockDomain Event, [expectedEvent]
    setUpSession()
    controller.params.id = 1
    Map model = controller.edit()
    assertEquals(expectedEvent, model.eventInstance)    
  }

  void testUpdate_eventDoesNotExist() {
    setUpEventAndSession()
    mockDomain(Volunteer, [mockSession.volunteer])
    controller.params.id = 999 // no object with id 999 exists
    controller.update()
    assertEquals('flash message',
            "Event not found with id ${controller.params.id}",
            mockFlash.message)
    assertEquals('redirect action',
            controller.edit, redirectArgs.action)
  }

  void testUpdate_NotOwner() {
    setUpEventAndSession()
    mockSession.volunteer.id = 99
    mockDomain(Volunteer, [mockSession.volunteer])
    controller.params.id = 1
    controller.update()
    assertEquals('flash message',
            "You can only update your own events",
            mockFlash.message)
    assertEquals('redirect action',
            controller.myEvents, redirectArgs.action)

  }

  void testUpdate_success() {
    Event expectedEvent = createEvent()
    mockDomain Event, [expectedEvent]
    setUpSession()
    mockDomain Volunteer, [mockSession.volunteer]
    controller.params.id = 1
    Map model = controller.update()
    assertEquals('flash message',
           "Event ${controller.params.id} updated",
            mockFlash.message)
    assertEquals('redirect action',
            controller.show, redirectArgs.action)

  }

  void testCreate() {
    mockDomain(Event)
    Map model = controller.create()
    assertNotNull('eventInstance', model.eventInstance)

  }

  void testSave_fail() {
    setUpSession()
    mockDomain(Volunteer, [mockSession.volunteer])
    mockDomain(Event)
    // mock out save method for non-happy path
    Event.metaClass.save = {-> return false}

    controller.save()

    assertEquals('render view', 'create', renderArgs.view)
    assertNotNull('eventInstance', renderArgs.model.eventInstance)

  }

  void testSave_success() {
    setUpSession()

    mockDomain(Volunteer, [mockSession.volunteer])
    mockDomain(Event)
    controller.params.name = "event1"
    controller.params.description = "e1d1 -- the description of the event"
    controller.params.location = "e1l1"
    controller.params.startDate = new Date()
    controller.params.endDate = new Date() + 7
    controller.params.owner = mockSession.volunteer
    // mock out save method for happy path
    Event.metaClass.save = {-> return true}

    controller.save()

    assertEquals('flash message',
           "Event ${controller.params.name} created",
            mockFlash.message)
    assertEquals('redirect controller', 'eventPosition', redirectArgs.controller)
    assertEquals('redirect action', 'create', redirectArgs.action)
  }

  void testCreatePosition() {
    controller.createPosition()
    assertEquals('redirect controller', 'eventPosition', redirectArgs.controller)
    assertEquals('redirect action', 'create', redirectArgs.action)
  }

  private def setUpEventAndSession() {
    Event expectedEvent = createEvent()
    mockSession.volunteer = new Volunteer()
    mockSession.volunteer.id = 1
    mockDomain(Event, [expectedEvent])
  }

  private def assertNoSuchEvent() {
    assertEquals('flash message',
            "Event not found with id ${controller.params.id}",
            mockFlash.message)
    assertEquals('redirect action',
            controller.myEvents, redirectArgs.action)
  }
  
  private def setUpSession() {
    mockSession.volunteer = new Volunteer()
    mockSession.volunteer.id = 1
  }

  Volunteer createVolunteer() {
   return new Volunteer(firstName: 'Bugs', lastName: 'Bunny', email: 'bugsbunny@warnerbros.com', password: 'bb')
  }

  Event[] createEventList() {
    def c = createVolunteer()
    def e1 = new Event(name: "event1", description: "e1d1 -- the description of the event", location: "e1l1", startDate: new Date(), endDate: new Date() + 7, owner: c)

    def e2 = new Event(name: "event2", description: "e2d1 -- the description of the event", location: "e2l1", startDate: new Date(), endDate: new Date() + 7, owner: c)
    def e3 = new Event(name: "event3", description: "e3d1 -- the description of the event", location: "e3l1", startDate: new Date(), endDate: new Date() + 30, owner: c)

    return [e1, e2, e3]
  }
  
  Event createEvent() {
    def c = createVolunteer()
    c.id = 1
    def e1 = new Event(name: "event1", description: "e1d1 -- the description of the event", location: "e1l1", startDate: new Date(), endDate: new Date() + 7, owner: c)
    return e1
  }
}
